#include "ota_version.h"
#include "ota_http_curl.h"
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <sys/reboot.h>
#include "log.h"
#include <unistd.h>

static char *gen_sha1(char *filepath)
{
    FILE *file = fopen(filepath, "rb");
    if (!file)
    {
        perror("无法打开文件");
        return NULL;
    }

    unsigned char buffer[4096];
    unsigned char digest[SHA_DIGEST_LENGTH];
    SHA_CTX sha_ctx;

    SHA1_Init(&sha_ctx);

    size_t bytesRead;
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0)
    {
        SHA1_Update(&sha_ctx, buffer, bytesRead);
    }

    fclose(file);

    SHA1_Final(digest, &sha_ctx);

    char *sha1_str = (char *)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!sha1_str)
    {
        perror("内存分配失败");
        return NULL;
    }

    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i)
    {
        sprintf(&sha1_str[i * 2], "%02x", digest[i]);
    }

    sha1_str[SHA_DIGEST_LENGTH * 2] = '\0';

    return sha1_str;
}

/**
 * @brief 检查并下载最新版本
1    查询ota服务器上的版本信息
2     解析 json, 和本地程序的版本进行比较
3    如果服务器的版本高  开始进行下载
4    执行下载
5    验证下载后的程序是否完整  （用下载文件生成一个验证码 sha1）
6    用本地生成的sha1 和 服务器上的sha1 码进行对比
7    如果一致   重启程序
*/
int ota_version_check_and_update()
{
    //1    查询ota服务器上的版本信息
    response_body_t *response_body = ota_http_curl_get(OTA_SERVER_URI_INFO);
    if (response_body == NULL)
    {
        perror("获得OTA服务器版本信息失败");
        return -1;
    }

    // 2     解析 json, 和本地程序的版本进行比较
    cJSON *root = cJSON_Parse(response_body->response_str);
    cJSON *major_cjson = cJSON_GetObjectItem(root, "major");
    cJSON *minor_cjson = cJSON_GetObjectItem(root, "minor");
    cJSON *patch_cjson = cJSON_GetObjectItem(root, "patch");
    int major_ota = major_cjson->valueint;
    int minor_ota = minor_cjson->valueint;
    int patch_ota = patch_cjson->valueint;
    if (major_ota > OTA_VERSION_MAJOR || (major_ota == OTA_VERSION_MAJOR && minor_ota > OTA_VERSION_MINOR) || (major_ota == OTA_VERSION_MAJOR && minor_ota == OTA_VERSION_MINOR && patch_ota > OTA_VERSION_PATCH))
    {
        // 3    如果服务器的版本高  开始进行下载
        // 4    执行下载
        int ret = ota_http_curl_download(OTA_SERVER_URI_DOWNLOAD, OTA_LOCAL_FILE_PATH);
        if (ret == 0)
        {
            log_info("下载成功\n");
            // 5    验证下载后的程序是否完整  （用下载文件生成一个验证码 sha1）
            char *sha1_local = gen_sha1(OTA_LOCAL_FILE_PATH);
            // 6    用本地生成的sha1 和 服务器上的sha1 码进行对比
            cJSON *sha1_ota_cjson = cJSON_GetObjectItem(root, "sha1");
            char *sha1_ota = sha1_ota_cjson->valuestring;
            if (strcmp(sha1_local, sha1_ota) == 0)
            {
                // 7    如果一致   重启程序
                log_info("sha1一致, 程序完整,重启程序\n");
                reboot(RB_AUTOBOOT);
            }
            else
            {
                log_info("sha1不一致, 程序不完整,删除下载文件\n");
                unlink(OTA_LOCAL_FILE_PATH);
                cJSON_Delete(root);
                free(response_body->response_str);
                free(sha1_local);
                free(response_body);
                return -1;
            }
        }
        else
        {
            log_error("下载失败\n");
            cJSON_Delete(root);
            free(response_body->response_str);
            free(response_body);
            return -1;
        }
    }
    cJSON_Delete(root);
    free(response_body->response_str);
    free(response_body);
    return 0;
}


/**
 * @brief 每日执行检查
 */
void ota_version_check_daily()
{
    while(1)
    {
        sleep(60 * 60 * 24);
        ota_version_check_and_update();
    }
}

/**
 * @brief 打印版本号
 */
void ota_version_print()
{
    printf("当前版本号:%d.%d.%d\n", OTA_VERSION_MAJOR, OTA_VERSION_MINOR, OTA_VERSION_PATCH);
}